<template>
  <div class="gantt-container">
    <div class="gantt-header">
      <h3>周时间计划甘特图</h3>
      <div class="header-controls">
        <el-button size="small" @click="clearAll">清空所有</el-button>
        <el-button size="small" type="primary" @click="exportData">导出数据</el-button>
      </div>
    </div>

    <div class="gantt-chart">
      <!-- 时间轴标尺 -->
      <div class="time-ruler">
        <div class="day-label-placeholder"></div>
        <div class="hour-labels">
          <div
            v-for="hour in 24"
            :key="hour"
            class="hour-label"
            :style="{ left: `${((hour - 1) / 24) * 100}%` }"
          >
            {{ hour - 1 }}:00
          </div>
        </div>
        <div class="actions-placeholder">操作</div>
      </div>

      <!-- 每天的甘特条 -->
      <div class="gantt-rows">
        <div
          v-for="(day, dayIndex) in weekDays"
          :key="day"
          class="gantt-row"
        >
          <div class="day-label">{{ day }}</div>
          <div class="gantt-timeline" @mousedown="startDrag(dayIndex, $event)">
            <svg
              :ref="el => setSvgRef(el, dayIndex)"
              width="100%"
              :height="rowHeight"
              class="gantt-svg"
              viewBox="0 0 2400 60"
              preserveAspectRatio="none"
            >
              <!-- 网格线 (0:00 到 24:00 共25条线，每条线在整点位置) -->
              <g class="grid-lines">
                <line
                  v-for="hour in 25"
                  :key="'v-' + hour"
                  :x1="(hour - 1) * 100"
                  :x2="(hour - 1) * 100"
                  :y1="0"
                  :y2="60"
                  stroke="#e4e7ed"
                  stroke-width="2"
                  vector-effect="non-scaling-stroke"
                />
              </g>

              <!-- 时间块 -->
              <g class="time-blocks">
                <g v-for="(block, blockIndex) in timeBlocks[dayIndex]" :key="blockIndex">
                  <!-- 时间块主体 -->
                  <rect
                    :x="block.startHour * 100"
                    :y="5"
                    :width="(block.endHour - block.startHour) * 100"
                    :height="50"
                    :fill="block.color"
                    stroke="#409eff"
                    stroke-width="2"
                    rx="4"
                    class="time-block"
                    @click.stop="selectBlock(dayIndex, blockIndex)"
                    @contextmenu.prevent="deleteBlock(dayIndex, blockIndex)"
                  />

                  <!-- 左边缘调整手柄 -->
                  <rect
                    :x="block.startHour * 100 - 3"
                    :y="5"
                    width="6"
                    :height="50"
                    fill="#409eff"
                    class="resize-handle resize-handle-left"
                    @mousedown.stop="startResize(dayIndex, blockIndex, 'left', $event)"
                  />

                  <!-- 右边缘调整手柄 -->
                  <rect
                    :x="block.endHour * 100 - 3"
                    :y="5"
                    width="6"
                    :height="50"
                    fill="#409eff"
                    class="resize-handle resize-handle-right"
                    @mousedown.stop="startResize(dayIndex, blockIndex, 'right', $event)"
                  />

                  <!-- 时间块文本 -->
                  <text
                    :x="(block.startHour + block.endHour) / 2 * 100"
                    :y="35"
                    text-anchor="middle"
                    fill="white"
                    font-size="12"
                    font-weight="bold"
                    class="block-text"
                  >
                    {{ block.label }}
                  </text>
                </g>
              </g>

              <!-- 选择框 -->
              <rect
                v-if="isDragging && currentDay === dayIndex"
                :x="Math.min(dragStartHour, dragCurrentHour) * 100"
                :y="5"
                :width="Math.abs(dragCurrentHour - dragStartHour) * 100"
                :height="50"
                fill="rgba(64, 158, 255, 0.3)"
                stroke="#409eff"
                stroke-width="2"
                stroke-dasharray="5,5"
                rx="4"
              />
            </svg>
          </div>

          <!-- 操作按钮 -->
          <div class="day-actions">
            <el-tooltip content="复制当天时间安排" placement="top">
              <el-button size="small" @click="copyDay(dayIndex)" :icon="CopyDocument">
                复制
              </el-button>
            </el-tooltip>
            <el-tooltip content="粘贴到当天" placement="top">
              <el-button size="small" @click="pasteDay(dayIndex)" :icon="Document" :disabled="!clipboard">
                粘贴
              </el-button>
            </el-tooltip>
            <el-tooltip content="删除当天所有时间块" placement="top">
              <el-button size="small" @click="deleteDay(dayIndex)" :icon="Delete" type="danger">
                删除
              </el-button>
            </el-tooltip>
          </div>
        </div>
      </div>
    </div>

    <!-- 编辑对话框 -->
    <el-dialog
      v-model="showEditDialog"
      title="编辑时间块"
      width="400px"
    >
      <el-form :model="editForm" label-width="80px">
        <el-form-item label="标签">
          <el-input v-model="editForm.label" placeholder="请输入标签名称" />
        </el-form-item>
        <el-form-item label="颜色">
          <el-color-picker v-model="editForm.color" />
        </el-form-item>
        <el-form-item label="开始时间">
          <el-time-picker
            v-model="editForm.startTimeValue"
            format="HH:mm"
            value-format="HH:mm"
            placeholder="选择时间"
            @change="handleTimeChange"
          />
        </el-form-item>
        <el-form-item label="结束时间">
          <el-time-picker
            v-model="editForm.endTimeValue"
            format="HH:mm"
            value-format="HH:mm"
            placeholder="选择时间"
            @change="handleTimeChange"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showEditDialog = false">取消</el-button>
        <el-button type="danger" @click="confirmDelete">删除</el-button>
        <el-button type="primary" @click="confirmEdit">确定</el-button>
      </template>
    </el-dialog>

    <!-- 使用说明 -->
    <div class="usage-tips">
      <el-alert type="info" :closable="false">
        <template #title>
          <strong>使用说明：</strong>
          在任意一天的时间轴上<strong>按住鼠标拖动</strong>选择时间段 |
          <strong>拖动时间块边缘</strong>调整大小 |
          <strong>点击</strong>时间块编辑时间 |
          <strong>右键</strong>时间块删除
        </template>
      </el-alert>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, computed } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { CopyDocument, Document, Delete } from '@element-plus/icons-vue';

// ==================== 常量配置 ====================
const weekDays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
const cellWidth = 40; // 每小时格子宽度（像素）
const rowHeight = 60; // 每行高度（像素）

// 时间块最小宽度配置
// 注意：此配置在 onDragEnd 函数中使用
// minWidth = cellWidth * 0.5 表示最小时间块为 30 分钟

// 响应式数据
const timeBlocks = ref([[], [], [], [], [], [], []]); // 7天的时间块
const clipboard = ref(null); // 剪贴板
const isDragging = ref(false);
const currentDay = ref(-1);
const dragStartX = ref(0); // 拖动起始位置（像素）
const dragCurrentX = ref(0); // 拖动当前位置（像素）
const dragStartHour = ref(0); // 拖动起始时间（小时）
const dragCurrentHour = ref(0); // 拖动当前时间（小时）
const showEditDialog = ref(false);
const selectedBlock = ref({ day: -1, index: -1 });
const svgRefs = ref([]); // SVG 元素引用数组

// 设置 SVG ref
const setSvgRef = (el, index) => {
  if (el) {
    svgRefs.value[index] = el;
  }
};

// 获取 SVG 实际宽度
const getSvgWidth = (dayIndex) => {
  const svg = svgRefs.value[dayIndex];
  return svg ? svg.getBoundingClientRect().width : cellWidth * 24;
};

const editForm = reactive({
  label: '',
  color: '#409eff',
  startTime: '',
  endTime: '',
  startTimeValue: '',
  endTimeValue: '',
});

// 调整大小相关
const isResizing = ref(false);
const resizeDay = ref(-1);
const resizeBlockIndex = ref(-1);
const resizeEdge = ref(''); // 'left' or 'right'
const resizeStartX = ref(0);

// 开始调整大小
const startResize = (dayIndex, blockIndex, edge, event) => {
  isResizing.value = true;
  resizeDay.value = dayIndex;
  resizeBlockIndex.value = blockIndex;
  resizeEdge.value = edge;

  resizeStartX.value = event.clientX;

  document.addEventListener('mousemove', onResizeMove);
  document.addEventListener('mouseup', onResizeEnd);
};

// 调整大小中
const onResizeMove = (event) => {
  if (!isResizing.value) return;

  const block = timeBlocks.value[resizeDay.value][resizeBlockIndex.value];
  const deltaX = event.clientX - resizeStartX.value;
  resizeStartX.value = event.clientX;

  if (resizeEdge.value === 'left') {
    // 调整左边缘
    const newStartX = Math.max(0, block.startX + deltaX);
    const newWidth = block.width - (newStartX - block.startX);

    // 最小宽度限制（15分钟）
    if (newWidth >= cellWidth * 0.25) {
      block.startX = newStartX;
      block.width = newWidth;
      block.startHour = block.startX / cellWidth;
      block.label = formatTimeRange(block.startHour, block.endHour);
    }
  } else if (resizeEdge.value === 'right') {
    // 调整右边缘
    const newWidth = Math.max(cellWidth * 0.25, block.width + deltaX);
    const maxHour = 23 + 59/60; // 23:59
    const maxWidth = (maxHour * cellWidth) - block.startX;

    block.width = Math.min(newWidth, maxWidth);
    block.endHour = (block.startX + block.width) / cellWidth;
    // 确保不超过23:59
    if (block.endHour > maxHour) {
      block.endHour = maxHour;
      block.width = (block.endHour - block.startHour) * cellWidth;
    }
    block.label = formatTimeRange(block.startHour, block.endHour);
  }
};

// 调整大小结束
const onResizeEnd = () => {
  if (!isResizing.value) return;

  document.removeEventListener('mousemove', onResizeMove);
  document.removeEventListener('mouseup', onResizeEnd);

  // 检查是否有重叠
  const block = timeBlocks.value[resizeDay.value][resizeBlockIndex.value];
  const hasOverlap = timeBlocks.value[resizeDay.value].some((b, idx) => {
    if (idx === resizeBlockIndex.value) return false;
    return !(block.endHour <= b.startHour || block.startHour >= b.endHour);
  });

  if (hasOverlap) {
    ElMessage.warning('调整后时间段重叠，已恢复原状态！');
    // 可以选择恢复原状态，这里简单提示
  }

  isResizing.value = false;
  ElMessage.success('时间块大小已调整！');
};

// 开始拖动（创建新时间块）
const startDrag = (dayIndex, event) => {
  // 如果正在调整大小，不创建新块
  if (isResizing.value) return;

  const rect = event.currentTarget.getBoundingClientRect();
  const x = event.clientX - rect.left;
  const width = rect.width;

  isDragging.value = true;
  currentDay.value = dayIndex;
  dragStartX.value = x;
  dragCurrentX.value = x;

  // 转换为小时
  dragStartHour.value = (x / width) * 24;
  dragCurrentHour.value = (x / width) * 24;

  document.addEventListener('mousemove', onDragMove);
  document.addEventListener('mouseup', onDragEnd);
};

// 拖动中
const onDragMove = (event) => {
  if (!isDragging.value) return;

  const timeline = document.querySelectorAll('.gantt-timeline')[currentDay.value];
  if (!timeline) return;

  const rect = timeline.getBoundingClientRect();
  let x = event.clientX - rect.left;
  const width = rect.width;

  // 限制在边界内
  x = Math.max(0, Math.min(x, width));
  dragCurrentX.value = x;

  // 转换为小时
  dragCurrentHour.value = (x / width) * 24;
};

/**
 * 拖动结束事件处理
 *
 * 功能说明：
 * 1. 处理三种拖动场景：
 *    - 点击（拖动距离 < 5px）：创建默认30分钟的时间块
 *    - 小范围拖动（5px ≤ 拖动距离 < 最小宽度）：自动扩展到30分钟
 *    - 正常拖动（拖动距离 ≥ 最小宽度）：按实际拖动距离创建
 *
 * 2. 边界处理：
 *    - 确保时间块不超出 0:00 - 23:59 范围
 *    - 超出右边界时自动向左调整
 *    - 超出左边界时从 0:00 开始
 *
 * 3. 最小时间块：30分钟（可在常量配置区域修改）
 */
const onDragEnd = () => {
  if (!isDragging.value) return;

  document.removeEventListener('mousemove', onDragMove);
  document.removeEventListener('mouseup', onDragEnd);

  let startHour = Math.min(dragStartHour.value, dragCurrentHour.value);
  let endHour = Math.max(dragStartHour.value, dragCurrentHour.value);
  let duration = endHour - startHour;

  // 定义最小时间块时长：30分钟（0.5小时）
  // 如需修改默认最小时长，请修改此处的倍数（如：1小时 = 1）
  const minDuration = 0.5;
  const maxHour = 23 + 59/60; // 23:59

  // 拖动距离（像素）
  const pixelDistance = Math.abs(dragCurrentX.value - dragStartX.value);

  // 如果拖动距离太小（小于5像素），视为点击事件，创建默认时长的时间块
  if (pixelDistance < 5) {
    // 以点击位置为起点，创建默认30分钟的时间块
    startHour = dragStartHour.value;
    endHour = startHour + minDuration;

    // 确保不超出右边界（23:59）
    if (endHour > maxHour) {
      // 如果超出，则向左调整起点
      endHour = maxHour;
      startHour = Math.max(0, maxHour - minDuration);
    }

    createTimeBlockByHours(currentDay.value, startHour, endHour);
  }
  // 如果拖动距离小于最小时长，但大于5像素，则扩展到最小时长
  else if (duration < minDuration) {
    // 保持拖动方向，向右或向左扩展到最小时长
    if (dragCurrentHour.value >= dragStartHour.value) {
      // 向右拖动，保持起点不变，扩展终点
      endHour = startHour + minDuration;
    } else {
      // 向左拖动，保持终点不变，扩展起点
      startHour = endHour - minDuration;
    }

    // 确保不超出边界（0:00 - 23:59）
    if (startHour < 0) {
      startHour = 0;
      endHour = Math.min(minDuration, maxHour);
    }
    if (endHour > maxHour) {
      endHour = maxHour;
      startHour = Math.max(0, maxHour - minDuration);
      if (endHour - startHour < 0.25) {
        // 如果剩余空间太小（小于15分钟），不创建
        isDragging.value = false;
        currentDay.value = -1;
        ElMessage.warning('选择的时间段太小，无法创建时间块！');
        return;
      }
    }

    createTimeBlockByHours(currentDay.value, startHour, endHour);
  }
  // 正常情况：拖动距离大于等于最小时长
  else {
    // 确保不超出边界
    if (endHour > maxHour) {
      endHour = maxHour;
    }
    createTimeBlockByHours(currentDay.value, startHour, endHour);
  }

  isDragging.value = false;
  currentDay.value = -1;
};

// 通过小时创建时间块（新方法）
const createTimeBlockByHours = (dayIndex, startHour, endHour) => {
  // 限制最大时间为23:59
  const maxHour = 23 + 59/60;
  if (endHour > maxHour) {
    endHour = maxHour;
  }

  // 检查重叠
  const hasOverlap = timeBlocks.value[dayIndex].some(block => {
    return !(endHour <= block.startHour || startHour >= block.endHour);
  });

  if (hasOverlap) {
    ElMessage.warning('时间段重叠，请重新选择！');
    return;
  }

  const block = {
    label: formatTimeRange(startHour, endHour),
    color: getRandomColor(),
    startHour,
    endHour,
  };

  timeBlocks.value[dayIndex].push(block);
  ElMessage.success('时间块创建成功！');
};

// 创建时间块（旧方法，保留兼容性）
const createTimeBlock = (dayIndex, startX, width) => {
  // 计算开始和结束时间
  let startHour = startX / cellWidth;
  let endHour = (startX + width) / cellWidth;

  createTimeBlockByHours(dayIndex, startHour, endHour);
};

// 格式化时间范围
const formatTimeRange = (startHour, endHour) => {
  const formatHour = (hour) => {
    const h = Math.floor(hour);
    const m = Math.round((hour - h) * 60);
    return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
  };
  return `${formatHour(startHour)}-${formatHour(endHour)}`;
};

// 获取随机颜色
const getRandomColor = () => {
  const colors = [
    '#409eff',
    '#67c23a',
    '#e6a23c',
    '#f56c6c',
    '#909399',
    '#c71585',
    '#20b2aa',
    '#ff6347',
    '#4169e1',
    '#32cd32',
  ];
  return colors[Math.floor(Math.random() * colors.length)];
};

// 选择时间块
const selectBlock = (dayIndex, blockIndex) => {
  selectedBlock.value = { day: dayIndex, index: blockIndex };
  const block = timeBlocks.value[dayIndex][blockIndex];

  editForm.label = block.label;
  editForm.color = block.color;
  editForm.startTime = formatHour(block.startHour);
  editForm.endTime = formatHour(block.endHour);
  editForm.startTimeValue = formatHour(block.startHour);
  editForm.endTimeValue = formatHour(block.endHour);

  showEditDialog.value = true;
};

// 格式化小时
const formatHour = (hour) => {
  const h = Math.floor(hour);
  const m = Math.round((hour - h) * 60);
  return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
};

// 删除时间块
const deleteBlock = (dayIndex, blockIndex) => {
  timeBlocks.value[dayIndex].splice(blockIndex, 1);
  ElMessage.success('时间块已删除！');
};

// 时间改变处理
const handleTimeChange = () => {
  // 验证时间有效性
  if (!editForm.startTimeValue || !editForm.endTimeValue) return;

  const [startH, startM] = editForm.startTimeValue.split(':').map(Number);
  const [endH, endM] = editForm.endTimeValue.split(':').map(Number);

  const startHour = startH + startM / 60;
  const endHour = endH + endM / 60;

  if (startHour >= endHour) {
    ElMessage.warning('结束时间必须大于开始时间！');
    return;
  }

  const maxHour = 23 + 59/60; // 23:59
  if (endHour > maxHour) {
    ElMessage.warning('结束时间不能超过23:59！');
    return;
  }

  // 更新显示时间
  editForm.startTime = editForm.startTimeValue;
  editForm.endTime = editForm.endTimeValue;
};

// 确认编辑
const confirmEdit = () => {
  const { day, index } = selectedBlock.value;
  if (day >= 0 && index >= 0) {
    const block = timeBlocks.value[day][index];

    // 如果修改了时间
    if (editForm.startTimeValue && editForm.endTimeValue) {
      const [startH, startM] = editForm.startTimeValue.split(':').map(Number);
      const [endH, endM] = editForm.endTimeValue.split(':').map(Number);

      const newStartHour = startH + startM / 60;
      let newEndHour = endH + endM / 60;

      if (newStartHour >= newEndHour) {
        ElMessage.warning('结束时间必须大于开始时间！');
        return;
      }

      // 限制最大时间为23:59
      const maxHour = 23 + 59/60;
      if (newEndHour > maxHour) {
        ElMessage.warning('结束时间不能超过23:59！');
        return;
      }

      // 检查是否与其他时间块重叠
      const hasOverlap = timeBlocks.value[day].some((b, idx) => {
        if (idx === index) return false;
        return !(newEndHour <= b.startHour || newStartHour >= b.endHour);
      });

      if (hasOverlap) {
        ElMessage.warning('时间段与其他时间块重叠！');
        return;
      }

      // 更新时间块
      block.startHour = newStartHour;
      block.endHour = newEndHour;
      block.startX = newStartHour * cellWidth;
      block.width = (newEndHour - newStartHour) * cellWidth;
      block.label = editForm.label || formatTimeRange(newStartHour, newEndHour);
    } else {
      block.label = editForm.label || formatTimeRange(block.startHour, block.endHour);
    }

    block.color = editForm.color;
    ElMessage.success('编辑成功！');
  }
  showEditDialog.value = false;
};

// 确认删除
const confirmDelete = () => {
  const { day, index } = selectedBlock.value;
  if (day >= 0 && index >= 0) {
    deleteBlock(day, index);
  }
  showEditDialog.value = false;
};

// 复制当天
const copyDay = (dayIndex) => {
  if (timeBlocks.value[dayIndex].length === 0) {
    ElMessage.warning('当天没有时间块，无法复制！');
    return;
  }

  // 深拷贝时间块
  clipboard.value = {
    dayName: weekDays[dayIndex],
    blocks: JSON.parse(JSON.stringify(timeBlocks.value[dayIndex])),
  };

  ElMessage.success(`已复制 ${weekDays[dayIndex]} 的 ${clipboard.value.blocks.length} 个时间块！`);
};

// 粘贴到当天
const pasteDay = (dayIndex) => {
  if (!clipboard.value) {
    ElMessage.warning('剪贴板为空，请先复制！');
    return;
  }

  const targetBlocks = timeBlocks.value[dayIndex];
  const pasteBlocks = clipboard.value.blocks;

  // 检查重叠
  const conflicts = [];
  pasteBlocks.forEach((pasteBlock, index) => {
    const hasOverlap = targetBlocks.some(existingBlock => {
      return !(pasteBlock.endHour <= existingBlock.startHour ||
               pasteBlock.startHour >= existingBlock.endHour);
    });

    if (hasOverlap) {
      conflicts.push({
        index: index + 1,
        label: pasteBlock.label,
      });
    }
  });

  if (conflicts.length > 0) {
    const conflictMessages = conflicts.map(c => `第${c.index}条: ${c.label}`).join('\n');
    ElMessageBox.alert(
      `以下时间块与现有时间段重叠：\n\n${conflictMessages}\n\n请删除当天时间块后再粘贴，或手动调整时间。`,
      '粘贴失败',
      {
        confirmButtonText: '知道了',
        type: 'warning',
      }
    );
    return;
  }

  // 粘贴成功
  timeBlocks.value[dayIndex] = [
    ...targetBlocks,
    ...pasteBlocks.map(block => ({ ...block })),
  ];

  ElMessage.success(
    `已将 ${clipboard.value.dayName} 的 ${pasteBlocks.length} 个时间块粘贴到 ${weekDays[dayIndex]}！`
  );
};

// 删除当天所有时间块
const deleteDay = (dayIndex) => {
  if (timeBlocks.value[dayIndex].length === 0) {
    ElMessage.warning('当天没有时间块！');
    return;
  }

  ElMessageBox.confirm(
    `确定要删除 ${weekDays[dayIndex]} 的所有 ${timeBlocks.value[dayIndex].length} 个时间块吗？`,
    '删除确认',
    {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    }
  )
    .then(() => {
      timeBlocks.value[dayIndex] = [];
      ElMessage.success(`已删除 ${weekDays[dayIndex]} 的所有时间块！`);
    })
    .catch(() => {
      // 取消删除
    });
};

// 清空所有
const clearAll = () => {
  timeBlocks.value = [[], [], [], [], [], [], []];
  clipboard.value = null;
  ElMessage.success('已清空所有时间块！');
};

// 导出数据
const exportData = () => {
  const data = timeBlocks.value.map((blocks, dayIndex) => ({
    day: weekDays[dayIndex],
    blocks: blocks.map(block => ({
      label: block.label,
      startTime: formatHour(block.startHour),
      endTime: formatHour(block.endHour),
      color: block.color,
    })),
  }));

  console.log('时间计划数据：', data);
  ElMessage.success('数据已导出到控制台！');

  // 也可以下载为JSON
  const dataStr = JSON.stringify(data, null, 2);
  const blob = new Blob([dataStr], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'weekly-schedule.json';
  a.click();
  URL.revokeObjectURL(url);
};
</script>

<style scoped>
.gantt-container {
  padding: 20px;
  background-color: #fff;
  border-radius: 8px;
}

.gantt-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding-bottom: 15px;
  border-bottom: 2px solid #e4e7ed;
}

.gantt-header h3 {
  margin: 0;
  color: #303133;
  font-size: 20px;
}

.header-controls {
  display: flex;
  gap: 10px;
}

.gantt-chart {
  overflow-x: auto;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
}

.time-ruler {
  display: flex;
  background-color: #f5f7fa;
  border-bottom: 2px solid #e4e7ed;
  position: sticky;
  top: 0;
  z-index: 10;
}

.day-label-placeholder {
  width: 80px;
  min-width: 80px;
  border-right: 2px solid #e4e7ed;
}

.actions-placeholder {
  padding: 10px 15px;
  font-size: 12px;
  color: #606266;
  font-weight: 600;
  text-align: center;
  min-width: 180px;
  width: 180px;
  border-left: 1px solid #e4e7ed;
}

.hour-labels {
  flex: 1;
  position: relative;
  height: 40px;
}

.hour-label {
  position: absolute;
  text-align: left;
  padding: 10px 0 10px 2px;
  font-size: 12px;
  color: #606266;
  font-weight: 600;
  white-space: nowrap;
}

.gantt-rows {
  background-color: #fff;
}

.gantt-row {
  display: flex;
  border-bottom: 1px solid #e4e7ed;
}

.gantt-row:last-child {
  border-bottom: none;
}

.day-label {
  width: 80px;
  min-width: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  color: #303133;
  background-color: #f5f7fa;
  border-right: 2px solid #e4e7ed;
  font-size: 14px;
}

.gantt-timeline {
  flex: 1;
  position: relative;
  cursor: crosshair;
  padding: 0;
  margin: 0;
}

.day-actions {
  display: flex;
  gap: 8px;
  padding: 0 10px;
  align-items: center;
  background-color: #fafafa;
  border-left: 1px solid #e4e7ed;
  min-width: 180px;
  width: 180px;
}

.gantt-svg {
  display: block;
  width: 100%;
  height: 100%;
}

.time-block {
  cursor: pointer;
  transition: opacity 0.2s;
}

.time-block:hover {
  opacity: 0.8;
}

.block-text {
  pointer-events: none;
  user-select: none;
}

.resize-handle {
  cursor: ew-resize;
  opacity: 0;
  transition: opacity 0.2s;
}

.time-blocks g:hover .resize-handle {
  opacity: 0.8;
}

.resize-handle:hover {
  opacity: 1 !important;
}

.usage-tips {
  margin-top: 20px;
}

:deep(.el-alert__title) {
  font-size: 14px;
}
</style>
